home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / render.c < prev    next >
C/C++ Source or Header  |  1998-11-09  |  53KB  |  2,031 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/render.c,v $
  15.  * $Revision: 1.7 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/11/09 22:20:40 $
  18.  *
  19.  * Sample setup for RCS header
  20.  *
  21.  * $Log: render.c,v $
  22.  * Revision 1.7  1998/11/09 22:20:40  nobody
  23.  * *** empty log message ***
  24.  *
  25.  * Revision 1.6  1998/08/08 15:45:37  nobody
  26.  * Activated the Editior
  27.  *
  28.  * Revision 1.5  1998/04/24 14:31:06  tfrieden
  29.  * Bugfixes
  30.  *
  31.  * Revision 1.4  1998/03/30 12:35:47  tfrieden
  32.  * Some warnings corrected
  33.  *
  34.  * Revision 1.3  1998/03/25 22:08:28  tfrieden
  35.  * Revision bumped to reflect new g3_project_point
  36.  *
  37.  * Revision 1.2  1998/03/22 16:12:21  hfrieden
  38.  * Slight modifications for tracking enforcer hits
  39.  *
  40.  * Revision 1.1.1.1  1998/03/03 15:12:30  nobody
  41.  * reimport after crash from backup
  42.  *
  43.  * Revision 1.1.1.1  1998/02/13  20:21:00  hfrieden
  44.  * Initial Import
  45.  */
  46.  
  47. #pragma off (unreferenced)
  48. static char rcsid[] = "$Id: render.c,v 1.7 1998/11/09 22:20:40 nobody Exp $";
  49. #pragma on (unreferenced)
  50.  
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <bsd/bsd.h>
  54.  
  55. #include "inferno.h"
  56. #include "segment.h"
  57. #include "error.h"
  58. #include "bm.h"
  59. #include "texmap.h"
  60. #include "mono.h"
  61. #include "render.h"
  62. #include "game.h"
  63. #include "object.h"
  64. #include "laser.h"
  65. #include "textures.h"
  66. #include "screens.h"
  67. #include "segpoint.h"
  68. #include "wall.h"
  69. #include "texmerge.h"
  70. #include "physics.h"
  71. #include "3d.h"
  72. #include "gameseg.h"
  73. #include "vclip.h"
  74. #include "lighting.h"
  75. #include "fuelcen.h"
  76. #include "newdemo.h"
  77. #include "automap.h"
  78. #include "endlevel.h"
  79. #include "key.h"
  80. #include "newmenu.h"
  81. #include "mem.h"
  82. #include "piggy.h"
  83.  
  84. #define INITIAL_LOCAL_LIGHT (F1_0/4)        // local light value in segment of occurence (of light emission)
  85.  
  86. #ifdef EDITOR
  87. #include "editor/editor.h"
  88. #endif
  89.  
  90. //used for checking if points have been rotated
  91. int Clear_window_color=-1;
  92. //int Clear_window=2;         //  1 = Clear whole background window, 2 = clear view portals into rest of world, 0 = no clear
  93. int Clear_window = 0;
  94. int RL_framecount=-1;
  95. short Rotated_last[MAX_VERTICES];
  96.  
  97. // When any render function needs to know what's looking at it, it should 
  98. // access Viewer members.
  99. object * Viewer = NULL;
  100.  
  101. vms_vector Viewer_eye;  //valid during render
  102.  
  103. int N_render_segs;
  104.  
  105. fix Render_zoom = 0x9000;                           //the player's zoom factor
  106.  
  107. #ifndef NDEBUG
  108. ubyte object_rendered[MAX_OBJECTS];
  109. #endif
  110.  
  111. #define DEFAULT_RENDER_DEPTH 16
  112. int Render_depth=DEFAULT_RENDER_DEPTH;          //how many segments deep to render
  113.  
  114. int Detriangulation_on = 1;                 // 1 = allow rendering of triangulated side as a quad, 0 = don't allow
  115.  
  116. #ifdef EDITOR
  117. int Render_only_bottom=0;
  118. int Bottom_bitmap_num = 9;
  119. #endif
  120.  
  121. fix Face_reflectivity = (F1_0/2);
  122.  
  123. short Ordered_rendered_object_list[MAX_RENDERED_OBJECTS];
  124.  
  125. #if 0       //this stuff could probably just be deleted
  126.  
  127. int inc_render_depth(void)
  128. {
  129.     return ++Render_depth;
  130. }
  131.  
  132. int dec_render_depth(void)
  133. {
  134.     return Render_depth==1?Render_depth:--Render_depth;
  135. }
  136.  
  137. int reset_render_depth(void)
  138. {
  139.     return Render_depth = DEFAULT_RENDER_DEPTH;
  140. }
  141.  
  142. #endif
  143.  
  144. #ifdef EDITOR
  145. int _search_mode = 0;           //true if looking for curseg,side,face
  146. short _search_x,_search_y;  //pixel we're looking at
  147. int found_seg,found_side,found_face,found_poly;
  148. #else
  149. #define _search_mode 0
  150. #endif
  151.  
  152. #ifdef NDEBUG       //if no debug code, set these vars to constants
  153.  
  154. #define Outline_mode 0
  155. #define Show_only_curside 0
  156.  
  157. #else
  158.  
  159. int Outline_mode=0,Show_only_curside=0;
  160.  
  161. int toggle_outline_mode(void)
  162. {
  163.     return Outline_mode = !Outline_mode;
  164. }
  165.  
  166. int toggle_show_only_curside(void)
  167. {
  168.     return Show_only_curside = !Show_only_curside;
  169. }
  170.  
  171. draw_outline(int nverts,g3s_point **pointlist)
  172. {
  173.     int i;
  174.  
  175.     gr_setcolor(BM_XRGB(63,63,63));
  176.  
  177.     for (i=0;i<nverts-1;i++)
  178.         g3_draw_line(pointlist[i],pointlist[i+1]);
  179.  
  180.     g3_draw_line(pointlist[i],pointlist[0]);
  181.  
  182. }
  183. #endif
  184.  
  185. grs_canvas * reticle_canvas = NULL;
  186.  
  187. void free_reticle_canvas()
  188. {
  189.     if (reticle_canvas) {
  190.         free( reticle_canvas->cv_bitmap.bm_data );
  191.         free( reticle_canvas );
  192.         reticle_canvas  = NULL;
  193.     }
  194. }
  195.  
  196. extern void show_reticle(int force_big);
  197.  
  198. // Draw the reticle in 3D for head tracking
  199. void draw_3d_reticle(fix eye_offset)
  200. {
  201.     g3s_point   reticle_points[4];
  202.     g3s_uvl     uvl[4];
  203.     g3s_point   *pointlist[4];
  204.     int             i;
  205.     vms_vector v1, v2;
  206.     grs_canvas *saved_canvas;
  207.     int saved_interp_method;
  208.  
  209. //  if (!Use_player_head_angles) return;
  210.     
  211.     for (i=0; i<4; i++ )    {
  212.         pointlist[i] = &reticle_points[i];
  213.         uvl[i].l = MAX_LIGHT;
  214.     }
  215.     uvl[0].u = 0; uvl[0].v = 0;
  216.     uvl[1].u = F1_0; uvl[1].v = 0;
  217.     uvl[2].u = F1_0; uvl[2].v = F1_0;
  218.     uvl[3].u = 0; uvl[3].v = F1_0;
  219.  
  220.     vm_vec_scale_add( &v1, &Viewer->pos, &Viewer->orient.fvec, F1_0*4 );
  221.     vm_vec_scale_add2(&v1,&Viewer->orient.rvec,eye_offset);
  222.  
  223.     vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
  224.     vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
  225.     g3_rotate_point(&reticle_points[0],&v2);
  226.  
  227.     vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
  228.     vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
  229.     g3_rotate_point(&reticle_points[1],&v2);
  230.  
  231.     vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
  232.     vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
  233.     g3_rotate_point(&reticle_points[2],&v2);
  234.  
  235.     vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
  236.     vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
  237.     g3_rotate_point(&reticle_points[3],&v2);
  238.  
  239.     if ( reticle_canvas == NULL )   {
  240.         reticle_canvas = gr_create_canvas(64,64);
  241.         if ( !reticle_canvas )
  242.             Error( "Couldn't malloc reticle_canvas" );
  243.         atexit( free_reticle_canvas );
  244.         reticle_canvas->cv_bitmap.bm_selector = 0;
  245.         reticle_canvas->cv_bitmap.bm_flags = BM_FLAG_TRANSPARENT;
  246.     }
  247.  
  248.     saved_canvas = grd_curcanv;
  249.     gr_set_current_canvas(reticle_canvas);
  250.     gr_clear_canvas( TRANSPARENCY_COLOR );     // Clear to Xparent
  251.     show_reticle(1);
  252.     gr_set_current_canvas(saved_canvas);
  253.     
  254.     saved_interp_method=Interpolation_method;
  255.     Interpolation_method    = 3;        // The best, albiet slowest.
  256.     g3_draw_tmap(4,pointlist,uvl,&reticle_canvas->cv_bitmap);
  257.     Interpolation_method    = saved_interp_method;
  258. }
  259.  
  260.  
  261. fix flash_scale;
  262.  
  263. #define FLASH_CYCLE_RATE f1_0
  264.  
  265. fix flash_rate = FLASH_CYCLE_RATE;
  266.  
  267. //cycle the flashing light for when mine destroyed
  268. void flash_frame()
  269. {
  270.     static fixang flash_ang=0;
  271.  
  272.     if (!Fuelcen_control_center_destroyed)
  273.         return;
  274.  
  275.     if (Endlevel_sequence)
  276.         return;
  277.  
  278.     if (PaletteBlueAdd > 10 )       //whiting out
  279.         return;
  280.  
  281. //  flash_ang += fixmul(FLASH_CYCLE_RATE,FrameTime);
  282.     flash_ang += fixmul(flash_rate,FrameTime);
  283.  
  284.     fix_fastsincos(flash_ang,&flash_scale,NULL);
  285.  
  286.     flash_scale = (flash_scale + f1_0)/2;
  287.  
  288. }
  289.  
  290. // -----------------------------------------------------------------------------------
  291. //  Render a face.
  292. //  It would be nice to not have to pass in segnum and sidenum, but they are used for our
  293. //  hideously hacked in headlight system.
  294. //  vp is a pointer to vertex ids.
  295. //  tmap1, tmap2 are texture map ids.  tmap2 is the pasty one.
  296. void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp, vms_vector *norm)
  297. {
  298.     fix         face_light;
  299.     grs_bitmap  *bm;
  300.     fix         reflect;
  301.     uvl         uvl_copy[8];
  302.     int         i;
  303.     g3s_point   *pointlist[8];
  304.  
  305.     Assert(nv <= 8);
  306.  
  307.     for (i=0; i<nv; i++) {
  308.         uvl_copy[i] = uvlp[i];
  309.         pointlist[i] = &Segment_points[vp[i]];
  310.     }
  311.  
  312.     face_light = -vm_vec_dot(&Viewer->orient.fvec,norm);
  313.  
  314.     if (tmap1 >= NumTextures) {
  315.         mprintf((0,"Invalid tmap number %d, NumTextures=%d, changing to 0\n",tmap1,NumTextures));
  316.         Int3();
  317.         Segments[segnum].sides[sidenum].tmap_num = 0;
  318.     }
  319.  
  320.     // New code for overlapping textures...
  321.     if (tmap2 != 0)
  322.         bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
  323.     else    {
  324.         bm = &GameBitmaps[Textures[tmap1].index];
  325.         PIGGY_PAGE_IN(Textures[tmap1]);
  326.     }
  327.  
  328.     Assert( !(bm->bm_flags & BM_FLAG_PAGED_OUT) );
  329.  
  330.     //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect)/2.0 + 0.5);
  331.     //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect));
  332.  
  333.     reflect = Face_reflectivity;        // f1_0;    //until we figure this stuff out...
  334.  
  335.     //set light values for each vertex & build pointlist
  336.     {
  337.         int i;
  338.  
  339.         face_light = fixmul(face_light,reflect);
  340.  
  341.         for (i=0;i<nv;i++) {
  342.  
  343.             //the uvl struct has static light already in it
  344.  
  345.             //scale static light for destruction effect
  346.             if (Fuelcen_control_center_destroyed)   //make lights flash
  347.                 uvl_copy[i].l = fixmul(flash_scale,uvl_copy[i].l);
  348.  
  349.             //add in dynamic light (from explosions, etc.)
  350.             uvl_copy[i].l += Dynamic_light[vp[i]];
  351.  
  352.             //add in light from player's headlight
  353.             uvl_copy[i].l += compute_headlight_light(&Segment_points[vp[i]].p3_vec,face_light);
  354.  
  355.             //saturate at max value
  356.             if (uvl_copy[i].l > MAX_LIGHT)
  357.                 uvl_copy[i].l = MAX_LIGHT;
  358.  
  359.         }
  360.     }
  361.  
  362.  
  363. #ifdef EDITOR
  364.     if ((Render_only_bottom) && (sidenum == WBOTTOM))
  365.         g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,&GameBitmaps[Textures[Bottom_bitmap_num].index]);
  366.     else
  367. #endif
  368.         g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,bm);
  369.  
  370.     #ifndef NDEBUG
  371.     if (Outline_mode) draw_outline(nv, pointlist);
  372.     #endif
  373. }
  374.  
  375. #ifdef EDITOR
  376. // -----------------------------------------------------------------------------------
  377. //  Only called if editor active.
  378. //  Used to determine which face was clicked on.
  379. void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp)
  380. {
  381.     int i;
  382.  
  383.     if (_search_mode) {
  384.         int save_lighting;
  385.         grs_bitmap *bm;
  386.         uvl uvl_copy[8];
  387.         g3s_point *pointlist[4];
  388.  
  389.         if (tmap2 > 0 )
  390.             bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
  391.         else
  392.             bm = &GameBitmaps[Textures[tmap1].index];
  393.  
  394.         for (i=0; i<nv; i++) {
  395.             uvl_copy[i] = uvlp[i];
  396.             pointlist[i] = &Segment_points[vp[i]];
  397.         }
  398.  
  399.         gr_setcolor(0);
  400.         gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
  401.         gr_setcolor(1);                 //and render in color one
  402.  save_lighting = Lighting_on;
  403.  Lighting_on = 2;
  404.         //g3_draw_poly(nv,vp);
  405.         g3_draw_tmap(nv,pointlist, uvl_copy, bm);
  406.  Lighting_on = save_lighting;
  407.  
  408.         if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) == 1) {
  409.             found_seg = segnum;
  410.             found_side = sidenum;
  411.             found_face = facenum;
  412.         }
  413.         
  414.     }
  415. }
  416. #endif
  417.  
  418. fix Tulate_min_dot = (F1_0/4);
  419. //--unused-- fix    Tulate_min_ratio = (2*F1_0);
  420. fix Min_n0_n1_dot   = (F1_0*15/16);
  421.  
  422. // -----------------------------------------------------------------------------------
  423. //  Render a side.
  424. //  Check for normal facing.  If so, render faces on side dictated by sidep->type.
  425. void render_side(segment *segp, int sidenum)
  426. {
  427.     short           vertnum_list[4];
  428.     side            *sidep = &segp->sides[sidenum];
  429.     vms_vector  tvec;
  430.     fix         v_dot_n0, v_dot_n1;
  431.     uvl         temp_uvls[3];
  432.     fix         min_dot, max_dot;
  433.     vms_vector  normals[2];
  434.  
  435.     if (!(WALL_IS_DOORWAY(segp,sidenum) & WID_RENDER_FLAG))     //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL)
  436.         return;
  437.  
  438.     #ifdef COMPACT_SEGS 
  439.         get_side_normals(segp, sidenum, &normals[0], &normals[1] );
  440.     #else
  441.         normals[0] = segp->sides[sidenum].normals[0];
  442.         normals[1] = segp->sides[sidenum].normals[1];
  443.     #endif
  444.  
  445.     //  Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
  446.     //  deal with it, get the dot product.
  447.     if (sidep->type == SIDE_IS_TRI_13)
  448.         vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
  449.     else
  450.         vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
  451.  
  452.     get_side_verts(vertnum_list,segp-Segments,sidenum);
  453.  
  454.     v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
  455.  
  456.     if (sidep->type == SIDE_IS_QUAD) {
  457.         if (v_dot_n0 >= 0) {
  458.             render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  459.             #ifdef EDITOR
  460.             check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  461.             #endif
  462.         }
  463.     } else {
  464.         //  Although this side has been triangulated, because it is not planar, see if it is acceptable
  465.         //  to render it as a single quadrilateral.  This is a function of how far away the viewer is, how non-planar
  466.         //  the face is, how normal to the surfaces the view is.
  467.         //  Now, if both dot products are close to 1.0, then render two triangles as a single quad.
  468.         v_dot_n1 = vm_vec_dot(&tvec, &normals[1]);
  469.  
  470.         if (v_dot_n0 < v_dot_n1) {
  471.             min_dot = v_dot_n0;
  472.             max_dot = v_dot_n1;
  473.         } else {
  474.             min_dot = v_dot_n1;
  475.             max_dot = v_dot_n0;
  476.         }
  477.  
  478.         //  Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio))
  479.         if (Detriangulation_on && ((min_dot+F1_0/256 > max_dot) || ((Viewer->segnum != segp-Segments) &&  (min_dot > Tulate_min_dot) && (max_dot < min_dot*2)))) {
  480.             fix n0_dot_n1;
  481.  
  482.             //  The other detriangulation code doesn't deal well with badly non-planar sides.
  483.             n0_dot_n1 = vm_vec_dot(&normals[0], &normals[1]);
  484.             if (n0_dot_n1 < Min_n0_n1_dot)
  485.                 goto im_so_ashamed;
  486.  
  487.             render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  488.             #ifdef EDITOR
  489.             check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  490.             #endif
  491.         } else {
  492. im_so_ashamed: ;
  493.             if (sidep->type == SIDE_IS_TRI_02) {
  494.                 if (v_dot_n0 >= 0) {
  495.                     render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  496.                     #ifdef EDITOR
  497.                     check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  498.                     #endif
  499.                 }
  500.  
  501.                 if (v_dot_n1 >= 0) {
  502.                     temp_uvls[0] = sidep->uvls[0];      temp_uvls[1] = sidep->uvls[2];      temp_uvls[2] = sidep->uvls[3];
  503.                     vertnum_list[1] = vertnum_list[2];  vertnum_list[2] = vertnum_list[3];  // want to render from vertices 0, 2, 3 on side
  504.                     render_face(segp-Segments, sidenum, 3, &vertnum_list[0], sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[1]);
  505.                     #ifdef EDITOR
  506.                     check_face(segp-Segments, sidenum, 1, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  507.                     #endif
  508.                 }
  509.             } else if (sidep->type ==  SIDE_IS_TRI_13) {
  510.                 if (v_dot_n1 >= 0) {
  511.                     render_face(segp-Segments, sidenum, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, &sidep->uvls[1], &normals[1]);  // rendering 1,2,3, so just skip 0
  512.                     #ifdef EDITOR
  513.                     check_face(segp-Segments, sidenum, 1, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  514.                     #endif
  515.                 }
  516.  
  517.                 if (v_dot_n0 >= 0) {
  518.                     temp_uvls[0] = sidep->uvls[0];      temp_uvls[1] = sidep->uvls[1];      temp_uvls[2] = sidep->uvls[3];
  519.                     vertnum_list[2] = vertnum_list[3];      // want to render from vertices 0,1,3
  520.                     render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[0]);
  521.                     #ifdef EDITOR
  522.                     check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  523.                     #endif
  524.                 }
  525.  
  526.             } else
  527.                 Error("Illegal side type in render_side, type = %i, segment # = %i, side # = %i\n", sidep->type, segp-Segments, sidenum);
  528.         }
  529.     }
  530.  
  531. }
  532.  
  533. #ifdef EDITOR
  534. render_object_search(object *obj)
  535. {
  536.     int changed=0;
  537.  
  538.     //note that we draw each pixel object twice, since we cannot control
  539.     //what color the object draws in, so we try color 0, then color 1,
  540.     //in case the object itself is rendering color 0
  541.  
  542.     gr_setcolor(0);
  543.     gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
  544.     render_object(obj);
  545.     if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 0)
  546.         changed=1;
  547.  
  548.     gr_setcolor(1);
  549.     gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
  550.     render_object(obj);
  551.     if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 1)
  552.         changed=1;
  553.  
  554.     if (changed) {
  555.         if (obj->segnum != -1)
  556.             Cursegp = &Segments[obj->segnum];
  557.         found_seg = -(obj-Objects+1);
  558.     }
  559. }
  560. #endif
  561.  
  562. do_render_object(int objnum)
  563. {
  564.     #ifdef EDITOR
  565.     int save_3d_outline;
  566.     #endif
  567.     object *obj = &Objects[objnum];
  568.     int count = 0;
  569.     int n;
  570.  
  571.     Assert(objnum < MAX_OBJECTS);
  572.  
  573.     #ifndef NDEBUG
  574.     if (object_rendered[objnum]) {      //already rendered this...
  575.         Int3();     //get Matt!!!
  576.         return;
  577.     }
  578.     object_rendered[objnum] = 1;
  579.     #endif
  580.  
  581.     //  Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so
  582.     //  that the guided missile system will know what objects to look at.
  583.     if ((Objects[objnum].type == OBJ_ROBOT) || (Objects[objnum].type == OBJ_PLAYER)) {
  584.         //Assert(Num_rendered_objects < MAX_RENDERED_OBJECTS);
  585.         //  This peculiar piece of code makes us keep track of the most recently rendered objects, which
  586.         //  are probably the higher priority objects, without overflowing the buffer
  587.         if (Num_rendered_objects >= MAX_RENDERED_OBJECTS) {
  588.             Int3();
  589.             Num_rendered_objects /= 2;
  590.         }
  591.         Ordered_rendered_object_list[Num_rendered_objects++] = objnum;
  592.     }
  593.  
  594.     if ((count++ > MAX_OBJECTS) || (obj->next == objnum)) {
  595.         Int3();                 // infinite loop detected
  596.         obj->next = -1;     // won't this clean things up?
  597.         return;                 // get out of this infinite loop!
  598.     }
  599.  
  600.         //g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size);
  601.  
  602.     //check for editor object
  603.  
  604.     #ifdef EDITOR
  605.     if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index) {
  606.         save_3d_outline = g3d_interp_outline;
  607.         g3d_interp_outline=1;
  608.     }
  609.     #endif
  610.  
  611.     #ifdef EDITOR
  612.     if (_search_mode)
  613.         render_object_search(obj);
  614.     else
  615.     #endif
  616.         //NOTE LINK TO ABOVE
  617.         render_object(obj);
  618.  
  619.     for (n=obj->attached_obj;n!=-1;n=Objects[n].ctype.expl_info.next_attach) {
  620.  
  621.         Assert(Objects[n].type == OBJ_FIREBALL);
  622.         Assert(Objects[n].control_type == CT_EXPLOSION);
  623.         Assert(Objects[n].flags & OF_ATTACHED);
  624.  
  625.         render_object(&Objects[n]);
  626.     }
  627.  
  628.  
  629.     #ifdef EDITOR
  630.     if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index)
  631.         g3d_interp_outline = save_3d_outline;
  632.     #endif
  633.  
  634.  
  635.     //DEBUG mprintf( (0, "%d ", objnum ));
  636.  
  637. }
  638.  
  639. #ifndef NDEBUG
  640. int draw_boxes=0;
  641. int window_check=1,draw_edges=0,new_seg_sorting=1,pre_draw_segs=0;
  642. int no_migrate_segs=1,migrate_objects=1,behind_check=1;
  643. int check_window_check=0;
  644. #else
  645. #define draw_boxes          0
  646. #define window_check            1
  647. #define draw_edges          0
  648. #define new_seg_sorting     1
  649. #define pre_draw_segs       0
  650. #define no_migrate_segs     1
  651. #define migrate_objects     1
  652. #define behind_check            1
  653. #define check_window_check  0
  654. #endif
  655.  
  656. //increment counter for checking if points rotated
  657. //This must be called at the start of the frame if rotate_list() will be used
  658. void render_start_frame()
  659. {
  660.     RL_framecount++;
  661.  
  662.     if (RL_framecount==0) {     //wrap!
  663.  
  664.         memset(Rotated_last,0,sizeof(Rotated_last));        //clear all to zero
  665.         RL_framecount=1;                                            //and set this frame to 1
  666.     }
  667. }
  668.  
  669. //Given a lit of point numbers, rotate any that haven't been rotated this frame
  670. g3s_codes rotate_list(int nv,short *pointnumlist)
  671. {
  672.     int i,pnum;
  673.     g3s_point *pnt;
  674.     g3s_codes cc;
  675.  
  676.     cc.and = 0xff;  cc.or = 0;
  677.  
  678.     for (i=0;i<nv;i++) {
  679.  
  680.         pnum = pointnumlist[i];
  681.  
  682.         pnt = &Segment_points[pnum];
  683.  
  684.         if (Rotated_last[pnum] != RL_framecount) {
  685.  
  686.             g3_rotate_point(pnt,&Vertices[pnum]);
  687.  
  688.             Rotated_last[pnum] = RL_framecount;
  689.         }
  690.  
  691.         cc.and &= pnt->p3_codes;
  692.         cc.or  |= pnt->p3_codes;
  693.     }
  694.  
  695.     return cc;
  696.  
  697. }
  698.  
  699. //Given a lit of point numbers, project any that haven't been projected
  700. void project_list(int nv,short *pointnumlist)
  701. {
  702.     int i,pnum;
  703.  
  704.     for (i=0;i<nv;i++) {
  705.  
  706.         pnum = pointnumlist[i];
  707.  
  708.         if (!(Segment_points[pnum].p3_flags & PF_PROJECTED))
  709.  
  710.             g3_project_point(&Segment_points[pnum]);
  711.  
  712.     }
  713. }
  714.  
  715.  
  716. // -----------------------------------------------------------------------------------
  717. void render_segment(int segnum)
  718. {
  719.     segment     *seg = &Segments[segnum];
  720.     g3s_codes   cc;
  721.     int         sn;
  722.  
  723.     Assert(segnum!=-1 && segnum<=Highest_segment_index);
  724.  
  725.     cc=rotate_list(8,&seg->verts);
  726.  
  727.     if (! cc.and) {     //all off screen?
  728.  
  729. //mprintf( (0, "!"));
  730.         //DEBUG mprintf( (0, "[Segment %d: ", segnum ));
  731.  
  732.         // set_segment_local_light_value(segnum,INITIAL_LOCAL_LIGHT);
  733.  
  734.         Automap_visited[segnum]=1;
  735.  
  736.         for (sn=0; sn<MAX_SIDES_PER_SEGMENT; sn++)
  737.             render_side(seg, sn);
  738.     }
  739.  
  740.     //draw any objects that happen to be in this segment
  741.  
  742.     //sort objects!
  743.     //object_sort_segment_objects( seg );
  744.         
  745.     #ifndef NDEBUG
  746.     if (!migrate_objects) {
  747.         int objnum;
  748.         for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
  749.             do_render_object(objnum);
  750.     }
  751.     #endif
  752.  
  753.     //DEBUG mprintf( (0, "]\n", segnum ));
  754.  
  755. }
  756.  
  757. // ----- This used to be called when Show_only_curside was set.
  758. // ----- It is wholly and superiorly replaced by render_side.
  759. // -- //render one side of one segment
  760. // -- void render_seg_side(segment *seg,int _side)
  761. // -- {
  762. // --   g3s_codes cc;
  763. // --   short vertnum_list[4];
  764. // -- 
  765. // --   cc=g3_rotate_list(8,&seg->verts);
  766. // -- 
  767. // --   if (! cc.and) {     //all off screen?
  768. // --       int fn,pn,i;
  769. // --       side *s;
  770. // --       face *f;
  771. // --       poly *p;
  772. // -- 
  773. // --       s=&seg->sides[_side];
  774. // -- 
  775. // --       for (f=s->faces,fn=s->num_faces;fn;fn--,f++)
  776. // --           for (p=f->polys,pn=f->num_polys;pn;pn--,p++) {
  777. // --               grs_bitmap *tmap;
  778. // --   
  779. // --               for (i=0;i<p->num_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]];
  780. // --   
  781. // --               if (p->tmap_num >= NumTextures) {
  782. // --                   Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures);
  783. // --                   p->tmap_num = 0;        //change it permanantly
  784. // --               }
  785. // --   
  786. // --               tmap = Textures[p->tmap_num];
  787. // --   
  788. // --               g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal);
  789. // --   
  790. // --               if (Outline_mode) draw_outline(p->num_vertices,vertnum_list);
  791. // --           }
  792. // --       }
  793. // -- 
  794. // -- }
  795.  
  796. #define CROSS_WIDTH  i2f(8)
  797. #define CROSS_HEIGHT i2f(8)
  798.  
  799. #ifndef NDEBUG
  800.  
  801. //draw outline for curside
  802. outline_seg_side(segment *seg,int _side,int edge,int vert)
  803. {
  804.     g3s_codes cc;
  805.  
  806.     cc=rotate_list(8,&seg->verts);
  807.  
  808.     if (! cc.and) {     //all off screen?
  809.         side *s;
  810.         g3s_point *pnt;
  811.  
  812.         s=&seg->sides[_side];
  813.  
  814.         //render curedge of curside of curseg in green
  815.  
  816.         gr_setcolor(BM_XRGB(0,63,0));
  817.         g3_draw_line(&Segment_points[seg->verts[Side_to_verts[_side][edge]]],&Segment_points[seg->verts[Side_to_verts[_side][(edge+1)%4]]]);
  818.  
  819.         //draw a little cross at the current vert
  820.  
  821.         pnt = &Segment_points[seg->verts[Side_to_verts[_side][vert]]];
  822.  
  823.         g3_project_point(pnt);      //make sure projected
  824.  
  825. //      gr_setcolor(BM_XRGB(0,0,63));
  826. //      gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
  827. //      gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
  828.  
  829.         gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT);
  830.         gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
  831.         gr_line(pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
  832.         gr_line(pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT,pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy);
  833.     }
  834. }
  835.  
  836. #endif
  837.  
  838. #if 0       //this stuff could probably just be deleted
  839.  
  840. #define DEFAULT_PERSPECTIVE_DEPTH 6
  841.  
  842. int Perspective_depth=DEFAULT_PERSPECTIVE_DEPTH;    //how many levels deep to render in perspective
  843.  
  844. int inc_perspective_depth(void)
  845. {
  846.     return ++Perspective_depth;
  847.  
  848. }
  849.  
  850. int dec_perspective_depth(void)
  851. {
  852.     return Perspective_depth==1?Perspective_depth:--Perspective_depth;
  853.  
  854. }
  855.  
  856. int reset_perspective_depth(void)
  857. {
  858.     return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH;
  859.  
  860. }
  861. #endif
  862.  
  863. typedef struct window {
  864.     short left,top,right,bot;
  865. } window;
  866.  
  867. ubyte code_window_point(fix x,fix y,window *w)
  868. {
  869.     ubyte code=0;
  870.  
  871.     if (x <= w->left)  code |= 1;
  872.     if (x >= w->right) code |= 2;
  873.  
  874.     if (y <= w->top) code |= 4;
  875.     if (y >= w->bot) code |= 8;
  876.  
  877.     return code;
  878. }
  879.  
  880. #ifndef NDEBUG
  881. draw_window_box(int color,short left,short top,short right,short bot)
  882. {
  883.     short l,t,r,b;
  884.  
  885.     gr_setcolor(color);
  886.  
  887.     l=left; t=top; r=right; b=bot;
  888.  
  889.     if ( r<0 || b<0 || l>=grd_curcanv->cv_bitmap.bm_w || t>=grd_curcanv->cv_bitmap.bm_h && b>=grd_curcanv->cv_bitmap.bm_h)
  890.         return;
  891.  
  892.     if (l<0) l=0;
  893.     if (t<0) t=0;
  894.     if (r>=grd_curcanv->cv_bitmap.bm_w) r=grd_curcanv->cv_bitmap.bm_w-1;
  895.     if (b>=grd_curcanv->cv_bitmap.bm_h) b=grd_curcanv->cv_bitmap.bm_h-1;
  896.  
  897.     gr_line(i2f(l),i2f(t),i2f(r),i2f(t));
  898.     gr_line(i2f(r),i2f(t),i2f(r),i2f(b));
  899.     gr_line(i2f(r),i2f(b),i2f(l),i2f(b));
  900.     gr_line(i2f(l),i2f(b),i2f(l),i2f(t));
  901.  
  902. }
  903. #endif
  904.  
  905. int matt_find_connect_side(int seg0,int seg1);
  906.  
  907. #ifndef NDEBUG
  908. char visited2[MAX_SEGMENTS];
  909. #endif
  910.  
  911. char visited[MAX_SEGMENTS];
  912. short Render_list[MAX_RENDER_SEGS];
  913. short Seg_depth[MAX_RENDER_SEGS];       //depth for each seg in Render_list
  914. ubyte processed[MAX_RENDER_SEGS];       //whether each entry has been processed
  915. int lcnt_save,scnt_save;
  916. //@@short *persp_ptr;
  917. short render_pos[MAX_SEGMENTS]; //where in render_list does this segment appear?
  918. //ubyte no_render_flag[MAX_RENDER_SEGS];
  919. window render_windows[MAX_RENDER_SEGS];
  920.  
  921. short render_obj_list[MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS][OBJS_PER_SEG];
  922.  
  923. //for objects
  924.  
  925.  
  926.  
  927. #define RED   BM_XRGB(63,0,0)
  928. #define WHITE BM_XRGB(63,63,63)
  929.  
  930. //Global vars for window clip test
  931. int Window_clip_left,Window_clip_top,Window_clip_right,Window_clip_bot;
  932.  
  933. //Given two sides of segment, tell the two verts which form the 
  934. //edge between them
  935. Two_sides_to_edge[6][6][2] = {
  936.     { {-1,-1}, {3,7}, {-1,-1}, {2,6}, {6,7}, {2,3} },
  937.     { {3,7}, {-1,-1}, {0,4}, {-1,-1}, {4,7}, {0,3} },
  938.     { {-1,-1}, {0,4}, {-1,-1}, {1,5}, {4,5}, {0,1} },
  939.     { {2,6}, {-1,-1}, {1,5}, {-1,-1}, {5,6}, {1,2} },
  940.     { {6,7}, {4,7}, {4,5}, {5,6}, {-1,-1}, {-1,-1} },
  941.     { {2,3}, {0,3}, {0,1}, {1,2}, {-1,-1}, {-1,-1} }
  942. };
  943.  
  944. //given an edge specified by two verts, give the two sides on that edge
  945. Edge_to_sides[8][8][2] = {
  946.     { {-1,-1}, {2,5}, {-1,-1}, {1,5}, {1,2}, {-1,-1}, {-1,-1}, {-1,-1} },
  947.     { {2,5}, {-1,-1}, {3,5}, {-1,-1}, {-1,-1}, {2,3}, {-1,-1}, {-1,-1} },
  948.     { {-1,-1}, {3,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {0,3}, {-1,-1} },
  949.     { {1,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {0,1} },
  950.     { {1,2}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {1,4} },
  951.     { {-1,-1}, {2,3}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {3,4}, {-1,-1} },
  952.     { {-1,-1}, {-1,-1}, {0,3}, {-1,-1}, {-1,-1}, {3,4}, {-1,-1}, {0,4} },
  953.     { {-1,-1}, {-1,-1}, {-1,-1}, {0,1}, {1,4}, {-1,-1}, {0,4}, {-1,-1} },
  954. };
  955.  
  956. //@@//perform simple check on tables
  957. //@@check_check()
  958. //@@{
  959. //@@    int i,j;
  960. //@@
  961. //@@    for (i=0;i<8;i++)
  962. //@@        for (j=0;j<8;j++)
  963. //@@            Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] && 
  964. //@@                    Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]);
  965. //@@
  966. //@@    for (i=0;i<6;i++)
  967. //@@        for (j=0;j<6;j++)
  968. //@@            Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] && 
  969. //@@                    Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]);
  970. //@@
  971. //@@
  972. //@@}
  973.  
  974.  
  975. //given an edge, tell what side is on that edge
  976. find_seg_side(segment *seg,short *verts,int notside)
  977. {
  978.     int i;
  979.     int vv0=-1,vv1=-1;
  980.     int side0,side1;
  981.     int *eptr;
  982.     int v0,v1;
  983.     short   *vp;
  984.  
  985. //@@    check_check();
  986.  
  987.     v0 = verts[0];
  988.     v1 = verts[1];
  989.     vp = seg->verts;
  990.  
  991.     for (i=0; i<8; i++) {
  992.         int svv = *vp++;    // seg->verts[i];
  993.  
  994.         if (vv0==-1 && svv == v0) {
  995.             vv0 = i;
  996.             if (vv1 != -1)
  997.                 break;
  998.         }
  999.  
  1000.         if (vv1==-1 && svv == v1) {
  1001.             vv1 = i;
  1002.             if (vv0 != -1)
  1003.                 break;
  1004.         }
  1005.     }
  1006.  
  1007.     Assert(vv0!=-1 && vv1!=-1);
  1008.  
  1009.     eptr = Edge_to_sides[vv0][vv1];
  1010.  
  1011.     side0 = eptr[0];
  1012.     side1 = eptr[1];
  1013.  
  1014.     Assert(side0!=-1 && side1!=-1);
  1015.  
  1016.     if (side0 != notside) {
  1017.         Assert(side1==notside);
  1018.         return side0;
  1019.     }
  1020.     else {
  1021.         Assert(side0==notside);
  1022.         return side1;
  1023.     }
  1024.  
  1025. }
  1026.  
  1027. //find the two segments that join a given seg though two sides, and
  1028. //the sides of those segments the abut. 
  1029. find_joining_side_norms(vms_vector *norm0_0,vms_vector *norm0_1,vms_vector *norm1_0,vms_vector *norm1_1,vms_vector **pnt0,vms_vector **pnt1,segment *seg,int s0,int s1)
  1030. {
  1031.     segment *seg0,*seg1;
  1032.     short edge_verts[2];
  1033.     int notside0,notside1;
  1034.     int edgeside0,edgeside1;
  1035.  
  1036.     Assert(s0!=-1 && s1!=-1);
  1037.  
  1038.     seg0 = &Segments[seg->children[s0]];
  1039.     seg1 = &Segments[seg->children[s1]];
  1040.  
  1041.     edge_verts[0] = seg->verts[Two_sides_to_edge[s0][s1][0]];
  1042.     edge_verts[1] = seg->verts[Two_sides_to_edge[s0][s1][1]];
  1043.  
  1044.     Assert(edge_verts[0]!=-1 && edge_verts[1]!=-1);
  1045.  
  1046.     notside0 = find_connect_side(seg,seg0);
  1047.     Assert(notside0 != -1);
  1048.     notside1 = find_connect_side(seg,seg1);
  1049.     Assert(notside1 != -1);
  1050.  
  1051.     edgeside0 = find_seg_side(seg0,edge_verts,notside0);
  1052.     edgeside1 = find_seg_side(seg1,edge_verts,notside1);
  1053.  
  1054.     //deal with the case where an edge is shared by more than two segments
  1055.  
  1056. //@@    if (IS_CHILD(seg0->children[edgeside0])) {
  1057. //@@        segment *seg00;
  1058. //@@        int notside00;
  1059. //@@
  1060. //@@        seg00 = &Segments[seg0->children[edgeside0]];
  1061. //@@
  1062. //@@        if (seg00 != seg1) {
  1063. //@@
  1064. //@@            notside00 = find_connect_side(seg0,seg00);
  1065. //@@            Assert(notside00 != -1);
  1066. //@@
  1067. //@@            edgeside0 = find_seg_side(seg00,edge_verts,notside00);
  1068. //@@            seg0 = seg00;
  1069. //@@        }
  1070. //@@
  1071. //@@    }
  1072. //@@
  1073. //@@    if (IS_CHILD(seg1->children[edgeside1])) {
  1074. //@@        segment *seg11;
  1075. //@@        int notside11;
  1076. //@@
  1077. //@@        seg11 = &Segments[seg1->children[edgeside1]];
  1078. //@@
  1079. //@@        if (seg11 != seg0) {
  1080. //@@            notside11 = find_connect_side(seg1,seg11);
  1081. //@@            Assert(notside11 != -1);
  1082. //@@
  1083. //@@            edgeside1 = find_seg_side(seg11,edge_verts,notside11);
  1084. //@@            seg1 = seg11;
  1085. //@@        }
  1086. //@@    }
  1087.  
  1088. //  if ( IS_CHILD(seg0->children[edgeside0]) ||
  1089. //        IS_CHILD(seg1->children[edgeside1])) 
  1090. //      return 0;
  1091.  
  1092.     #ifdef COMPACT_SEGS
  1093.         get_side_normals(seg0, edgeside0, norm0_0, norm0_1 );
  1094.         get_side_normals(seg1, edgeside1, norm1_0, norm1_1 );
  1095.     #else 
  1096.         *norm0_0 = seg0->sides[edgeside0].normals[0];
  1097.         *norm0_1 = seg0->sides[edgeside0].normals[1];
  1098.         *norm1_0 = seg1->sides[edgeside1].normals[0];
  1099.         *norm1_1 = seg1->sides[edgeside1].normals[1];
  1100.     #endif
  1101.  
  1102.     *pnt0 = &Vertices[seg0->verts[Side_to_verts[edgeside0][seg0->sides[edgeside0].type==3?1:0]]];
  1103.     *pnt1 = &Vertices[seg1->verts[Side_to_verts[edgeside1][seg1->sides[edgeside1].type==3?1:0]]];
  1104.  
  1105.     return 1;
  1106. }
  1107.  
  1108. //see if the order matters for these two children.
  1109. //returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0
  1110. compare_children(segment *seg,short c0,short c1)
  1111. {
  1112.     vms_vector norm0_0,norm0_1,*pnt0,temp;
  1113.     vms_vector norm1_0,norm1_1,*pnt1;
  1114.     fix d0_0,d0_1,d1_0,d1_1,d0,d1;
  1115. int t;
  1116.  
  1117.     if (Side_opposite[c0] == c1) return 0;
  1118.  
  1119.     Assert(c0!=-1 && c1!=-1);
  1120.  
  1121.     //find normals of adjoining sides
  1122.  
  1123.     t = find_joining_side_norms(&norm0_0,&norm0_1,&norm1_0,&norm1_1,&pnt0,&pnt1,seg,c0,c1);
  1124.  
  1125. //if (!t)
  1126. // return 0;
  1127.  
  1128.     vm_vec_sub(&temp,&Viewer_eye,pnt0);
  1129.     d0_0 = vm_vec_dot(&norm0_0,&temp);
  1130.     d0_1 = vm_vec_dot(&norm0_1,&temp);
  1131.  
  1132.     vm_vec_sub(&temp,&Viewer_eye,pnt1);
  1133.     d1_0 = vm_vec_dot(&norm1_0,&temp);
  1134.     d1_1 = vm_vec_dot(&norm1_1,&temp);
  1135.  
  1136.     d0 = (d0_0 < 0 || d0_1 < 0)?-1:1;
  1137.     d1 = (d1_0 < 0 || d1_1 < 0)?-1:1;
  1138.  
  1139.     if (d0 < 0 && d1 < 0)
  1140.         return 0;
  1141.  
  1142.     if (d0 < 0)
  1143.         return 1;
  1144.     else if (d1 < 0)
  1145.         return -1;
  1146.     else
  1147.         return 0;
  1148.  
  1149. }
  1150.  
  1151. int ssc_total=0,ssc_swaps=0;
  1152.  
  1153. //short the children of segment to render in the correct order
  1154. //returns non-zero if swaps were made
  1155. int sort_seg_children(segment *seg,int n_children,short *child_list)
  1156. {
  1157.     int i,j;
  1158.     int r;
  1159.     int made_swaps,count;
  1160.  
  1161.     if (n_children == 0) return 0;
  1162.  
  1163.  ssc_total++;
  1164.  
  1165.     //for each child,  compare with other children and see if order matters
  1166.     //if order matters, fix if wrong
  1167.  
  1168.     count = 0;
  1169.  
  1170.     do {
  1171.         made_swaps = 0;
  1172.  
  1173.         for (i=0;i<n_children-1;i++)
  1174.             for (j=i+1;child_list[i]!=-1 && j<n_children;j++)
  1175.                 if (child_list[j]!=-1) {
  1176.                     r = compare_children(seg,child_list[i],child_list[j]);
  1177.  
  1178.                     if (r == 1) {
  1179.                         int temp = child_list[i];
  1180.                         child_list[i] = child_list[j];
  1181.                         child_list[j] = temp;
  1182.                         made_swaps=1;
  1183.                     }
  1184.                 }
  1185.  
  1186.     } while (made_swaps && ++count<n_children);
  1187.  
  1188.  if (count)
  1189.   ssc_swaps++;
  1190.  
  1191.     return count;
  1192. }
  1193.  
  1194. add_obj_to_seglist(int objnum,int listnum)
  1195. {
  1196.     int i,checkn,marker;
  1197.  
  1198.     checkn = listnum;
  1199.  
  1200.     //first, find a slot
  1201.  
  1202. //mprintf((0,"adding obj %d to %d",objnum,listnum));
  1203.  
  1204.     do {
  1205.  
  1206.         for (i=0;render_obj_list[checkn][i] >= 0;i++);
  1207.     
  1208.         Assert(i < OBJS_PER_SEG);
  1209.     
  1210.         marker = render_obj_list[checkn][i];
  1211.  
  1212.         if (marker != -1) {
  1213.             checkn = -marker;
  1214.             //Assert(checkn < MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
  1215.             if (checkn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
  1216.                 Int3();
  1217.                 return;
  1218.             }
  1219.         }
  1220.  
  1221.     } while (marker != -1);
  1222.  
  1223. //mprintf((0,"  slot %d,%d",checkn,i));
  1224.  
  1225.  
  1226.     //now we have found a slot.  put object in it
  1227.  
  1228.     if (i != OBJS_PER_SEG-1) {
  1229.  
  1230.         render_obj_list[checkn][i] = objnum;
  1231.         render_obj_list[checkn][i+1] = -1;
  1232.     }
  1233.     else {              //chain to additional list
  1234.         int lookn;
  1235.  
  1236.         //find an available sublist
  1237.  
  1238.         for (lookn=MAX_RENDER_SEGS;render_obj_list[lookn][0]!=-1 && lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;lookn++);
  1239.  
  1240.         //Assert(lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
  1241.         if (lookn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
  1242.             Int3();
  1243.             return;
  1244.         }
  1245.  
  1246.         render_obj_list[checkn][i] = -lookn;
  1247.         render_obj_list[lookn][0] = objnum;
  1248.         render_obj_list[lookn][1] = -1;
  1249.  
  1250.     }
  1251.  
  1252. //mprintf((0,"  added!\n"));
  1253.  
  1254. }
  1255.  
  1256. #define SORT_LIST_SIZE 50
  1257.  
  1258. typedef struct sort_item {
  1259.     int objnum;
  1260.     fix dist;
  1261. } sort_item;
  1262.  
  1263. sort_item sort_list[SORT_LIST_SIZE];
  1264. int n_sort_items;
  1265.  
  1266. //compare function for object sort. 
  1267. int sort_func(sort_item *a,sort_item *b)
  1268. {
  1269.     fix delta_dist;
  1270.     object *obj_a,*obj_b;
  1271.  
  1272.     delta_dist = a->dist - b->dist;
  1273.  
  1274.     obj_a = &Objects[a->objnum];
  1275.     obj_b = &Objects[b->objnum];
  1276. /*    if (a->objnum>MAX_OBJECTS) printf("Error: Object %d out of range\n", a->objnum);
  1277.     if (b->objnum>MAX_OBJECTS) printf("Error: Object %d out of range\n", b->objnum);*/
  1278.  
  1279.     if (a->objnum<0 || a->objnum>MAX_OBJECTS ||
  1280.         b->objnum<0 || b->objnum>MAX_OBJECTS) {
  1281.         // Something`s really scrwed up here. This shouldn`t hapen.
  1282.         // This is just to get a defined state for the compare,
  1283.         // to keep qsort from looping ad infinitum
  1284.         printf("Warning: Object list damaged: %d - %d\n", a->objnum, b->objnum);
  1285.         if (a->objnum>b->objnum) return -1;
  1286.         else                     return 1;
  1287.     }
  1288.  
  1289.     // ENFORCER: The following line sometimes causes an enforcer hit
  1290.     if (abs(delta_dist) < (obj_a->size + obj_b->size)) {        //same position
  1291.  
  1292.         //these two objects are in the same position.  see if one is a fireball
  1293.         //or laser or something that should plot on top
  1294.  
  1295.         if (obj_a->type == OBJ_WEAPON || obj_a->type == OBJ_FIREBALL)
  1296.             if (!(obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL))
  1297.                 return -1;  //a is weapon, b is not, so say a is closer
  1298.             else;               //both are weapons 
  1299.         else
  1300.             if (obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL)
  1301.                 return 1;   //b is weapon, a is not, so say a is farther
  1302.  
  1303.         //no special case, fall through to normal return
  1304.     }
  1305.  
  1306.     return delta_dist;  //return distance
  1307. }
  1308.  
  1309. build_object_lists(int n_segs)
  1310. {
  1311.     int nn;
  1312.  
  1313. //mprintf((0,"build n_segs=%d",n_segs));
  1314.  
  1315.     for (nn=0;nn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;nn++)
  1316.         render_obj_list[nn][0] = -1;
  1317.  
  1318.     for (nn=0;nn<n_segs;nn++) {
  1319.         int segnum;
  1320.  
  1321.         segnum = Render_list[nn];
  1322.  
  1323. //mprintf((0,"nn=%d seg=%d ",nn,segnum));
  1324.  
  1325.         if (segnum != -1) {
  1326.             int objnum;
  1327.             object *obj;
  1328.  
  1329.             for (objnum=Segments[segnum].objects;objnum!=-1;objnum = obj->next) {
  1330.                 int new_segnum,did_migrate,list_pos;
  1331.  
  1332.                 obj = &Objects[objnum];
  1333.  
  1334.                 Assert( obj->segnum == segnum );
  1335.  
  1336.                 if (obj->flags & OF_ATTACHED)
  1337.                     continue;       //ignore this object
  1338.  
  1339.                 new_segnum = segnum;
  1340.                 list_pos = nn;
  1341.  
  1342. //mprintf((0,"objnum=%d ",objnum));
  1343.                 if (obj->type != OBJ_CNTRLCEN)      //don't migrate controlcen
  1344.                 do {
  1345.                     segmasks m;
  1346.  
  1347.                     did_migrate = 0;
  1348.     
  1349.                     m = get_seg_masks(&obj->pos,new_segnum,obj->size);
  1350.     
  1351.                     if (m.sidemask) {
  1352.                         int sn,sf;
  1353.  
  1354.                         for (sn=0,sf=1;sn<6;sn++,sf<<=1)
  1355.                             if (m.sidemask & sf) {
  1356.                                 segment *seg = &Segments[obj->segnum];
  1357.         
  1358.                                 if (WALL_IS_DOORWAY(seg,sn) & WID_FLY_FLAG) {       //can explosion migrate through
  1359.                                     int child = seg->children[sn];
  1360.                                     int checknp;
  1361.         
  1362.                                     for (checknp=list_pos;checknp--;)
  1363.                                         if (Render_list[checknp] == child) {
  1364. //mprintf((0,"mig from %d to %d ",new_segnum,child));
  1365.                                             new_segnum = child;
  1366.                                             list_pos = checknp;
  1367.                                             did_migrate = 1;
  1368.                                         }
  1369.                                 }
  1370.                             }
  1371.                     }
  1372.     
  1373.                 } while (did_migrate);
  1374.  
  1375.                 add_obj_to_seglist(objnum,list_pos);
  1376.     
  1377.             }
  1378.  
  1379.         }
  1380.     }
  1381.  
  1382. //mprintf((0,"done build "));
  1383.  
  1384.     //now that there's a list for each segment, sort the items in those lists
  1385.     for (nn=0;nn<n_segs;nn++) {
  1386.         int segnum;
  1387.  
  1388.         segnum = Render_list[nn];
  1389.  
  1390. //mprintf((0,"nn=%d seg=%d ",nn,segnum));
  1391.  
  1392.         if (segnum != -1) {
  1393.             int t,lookn,i,n;
  1394.  
  1395.             //first count the number of objects & copy into sort list
  1396.  
  1397.             lookn = nn;
  1398.             i = n_sort_items = 0;
  1399.             while ((t=render_obj_list[lookn][i++])!=-1)
  1400.                 if (t<0)
  1401.                     {lookn = -t; i=0;}
  1402.                 else
  1403.                     if (n_sort_items < SORT_LIST_SIZE-1) {      //add if room
  1404.                         sort_list[n_sort_items].objnum = t;
  1405.                         //NOTE: maybe use depth, not dist - quicker computation
  1406.                         sort_list[n_sort_items].dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
  1407.                         n_sort_items++;
  1408.                     }
  1409.  
  1410.  
  1411.             //now call qsort
  1412.  
  1413.             qsort(sort_list,n_sort_items,sizeof(*sort_list),sort_func);
  1414.  
  1415.             //now copy back into list
  1416.  
  1417.             lookn = nn;
  1418.             i = 0;
  1419.             n = n_sort_items;
  1420.             while ((t=render_obj_list[lookn][i])!=-1 && n>0)
  1421.                 if (t<0)
  1422.                     {lookn = -t; i=0;}
  1423.                 else
  1424.                     render_obj_list[lookn][i++] = sort_list[--n].objnum;
  1425.             render_obj_list[lookn][i] = -1; //mark (possibly new) end
  1426.         }
  1427.     }
  1428. }
  1429.  
  1430. int Use_player_head_angles = 0;
  1431. vms_angvec Player_head_angles;
  1432.  
  1433. extern int Num_tmaps_drawn;
  1434. extern int Total_pixels;
  1435. //--unused-- int Total_num_tmaps_drawn=0;
  1436.  
  1437. int Rear_view=0;
  1438.  
  1439. #ifdef JOHN_ZOOM
  1440. fix Zoom_factor=F1_0;
  1441. #endif
  1442. //renders onto current canvas
  1443. void render_frame(fix eye_offset)
  1444. {
  1445.     int start_seg_num;
  1446.  
  1447. //Total_num_tmaps_drawn += Num_tmaps_drawn;
  1448. //if ((FrameCount > 0) && (Total_num_tmaps_drawn))
  1449. //  mprintf((0, "Frame: %4i, total = %6i, Avg = %7.3f, Avgpix=%7.3f\n", Num_tmaps_drawn, Total_num_tmaps_drawn, (float) Total_num_tmaps_drawn/FrameCount, (float) Total_pixels/Total_num_tmaps_drawn));
  1450. //Num_tmaps_drawn = 0;
  1451.  
  1452.     if (Endlevel_sequence) {
  1453.         render_endlevel_frame(eye_offset);
  1454.         FrameCount++;
  1455.         return;
  1456.     }
  1457.  
  1458. #ifdef NEWDEMO
  1459.     if ( Newdemo_state == ND_STATE_RECORDING )  {
  1460.         if (eye_offset >= 0 )   {
  1461.             newdemo_record_start_frame(FrameCount, FrameTime );
  1462.             newdemo_record_viewer_object(Viewer);
  1463.         }
  1464.     }
  1465. #endif
  1466.  
  1467.     g3_start_frame();
  1468.  
  1469.     Viewer_eye = Viewer->pos;
  1470.  
  1471. //  if (Viewer->type == OBJ_PLAYER && (Cockpit_mode!=CM_REAR_VIEW))
  1472. //      vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
  1473.  
  1474.     if (eye_offset) {
  1475.         vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
  1476.     }
  1477.  
  1478.     #ifdef EDITOR
  1479.     if (Function_mode==FMODE_EDITOR)
  1480.         Viewer_eye = Viewer->pos;
  1481.     #endif
  1482.  
  1483.     start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
  1484.  
  1485.     if (start_seg_num==-1)
  1486.         start_seg_num = Viewer->segnum;
  1487.  
  1488.     if (Viewer==ConsoleObject && Use_player_head_angles) {
  1489.         vms_matrix headm,viewm;
  1490.         vm_angles_2_matrix(&headm,&Player_head_angles);
  1491.         vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
  1492.         g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
  1493.     //@@} else if ((Cockpit_mode==CM_REAR_VIEW) && (Viewer==ConsoleObject)) {
  1494.     } else if (Rear_view && (Viewer==ConsoleObject)) {
  1495.         vms_matrix headm,viewm;
  1496.         Player_head_angles.p = Player_head_angles.b = 0;
  1497.         Player_head_angles.h = 0x7fff;
  1498.         vm_angles_2_matrix(&headm,&Player_head_angles);
  1499.         vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
  1500.         g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
  1501.     } else  {
  1502. #ifdef JOHN_ZOOM
  1503.         if (keyd_pressed[KEY_RSHIFT] )  {
  1504.             Zoom_factor += FrameTime*4;
  1505.             if (Zoom_factor > F1_0*5 ) Zoom_factor=F1_0*5;
  1506.         } else {
  1507.             Zoom_factor -= FrameTime*4;
  1508.             if (Zoom_factor < F1_0 ) Zoom_factor = F1_0;
  1509.         }
  1510.         g3_set_view_matrix(&Viewer_eye,&Viewer->orient,fixdiv(Render_zoom,Zoom_factor));
  1511. #else
  1512.         g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
  1513. #endif
  1514.     }
  1515.  
  1516.     if (Clear_window == 1) {
  1517.         if (Clear_window_color == -1)
  1518.             Clear_window_color = BM_XRGB(0, 0, 0);  //BM_XRGB(31, 15, 7);
  1519.         gr_clear_canvas(Clear_window_color);
  1520.     }
  1521.  
  1522.     render_mine(start_seg_num,eye_offset);
  1523.  
  1524.     if (Use_player_head_angles )
  1525.         draw_3d_reticle(eye_offset);
  1526.  
  1527.     g3_end_frame();
  1528.  
  1529.     FrameCount++;       //we have rendered a frame
  1530. }
  1531.  
  1532. int first_terminal_seg;
  1533.  
  1534. //build a list of segments to be rendered
  1535. //fills in Render_list & N_render_segs
  1536. build_segment_list(int start_seg_num)
  1537. {
  1538.     int lcnt,scnt,ecnt;
  1539.     int l,c;
  1540.     int ch;
  1541.  
  1542.     memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1));
  1543.     memset(render_pos, -1, sizeof(render_pos[0])*(Highest_segment_index+1));
  1544.     //memset(no_render_flag, 0, sizeof(no_render_flag[0])*(MAX_RENDER_SEGS));
  1545.     memset(processed, 0, sizeof(processed));
  1546.  
  1547.     #ifndef NDEBUG
  1548.     memset(visited2, 0, sizeof(visited2[0])*(Highest_segment_index+1));
  1549.     #endif
  1550.  
  1551.     lcnt = scnt = 0;
  1552.  
  1553.     Render_list[lcnt] = start_seg_num; visited[start_seg_num]=1;
  1554.     Seg_depth[lcnt] = 0;
  1555.     lcnt++;
  1556.     ecnt = lcnt;
  1557.     render_pos[start_seg_num] = 0;
  1558.  
  1559.     #ifndef NDEBUG
  1560.     if (pre_draw_segs)
  1561.         render_segment(start_seg_num);
  1562.     #endif
  1563.  
  1564.     render_windows[0].left=render_windows[0].top=0;
  1565.     render_windows[0].right=grd_curcanv->cv_bitmap.bm_w-1;
  1566.     render_windows[0].bot=grd_curcanv->cv_bitmap.bm_h-1;
  1567.  
  1568.     //breadth-first renderer
  1569.  
  1570.     //build list
  1571.  
  1572.     for (l=0;l<Render_depth;l++) {
  1573.  
  1574.         //while (scnt < ecnt) {
  1575.         for (scnt=0;scnt < ecnt;scnt++) {
  1576.             int rotated,segnum;
  1577.             window *check_w;
  1578.             short child_list[MAX_SIDES_PER_SEGMENT];        //list of ordered sides to process
  1579.             int n_children;                                     //how many sides in child_list
  1580.             segment *seg;
  1581.  
  1582.             if (processed[scnt])
  1583.                 continue;
  1584.  
  1585.             processed[scnt]=1;
  1586.  
  1587.             segnum = Render_list[scnt];
  1588.             check_w = &render_windows[scnt];
  1589.  
  1590.             #ifndef NDEBUG
  1591.             if (draw_boxes)
  1592.                 draw_window_box(RED,check_w->left,check_w->top,check_w->right,check_w->bot);
  1593.             #endif
  1594.  
  1595.             if (segnum == -1) continue;
  1596.  
  1597.             seg = &Segments[segnum];
  1598.             rotated=0;
  1599.  
  1600.             //look at all sides of this segment.
  1601.             //tricky code to look at sides in correct order follows
  1602.  
  1603.             for (c=n_children=0;c<MAX_SIDES_PER_SEGMENT;c++) {      //build list of sides
  1604.                 int wid;
  1605.  
  1606.                 wid = WALL_IS_DOORWAY(seg, c);
  1607.  
  1608.                 ch=seg->children[c];
  1609.  
  1610.                 if ( (window_check || !visited[ch]) && (wid & WID_RENDPAST_FLAG) ) {
  1611.                     if (behind_check) {
  1612.                         byte *sv = Side_to_verts[c];
  1613.                         ubyte codes_and=0xff;
  1614.                         int i;
  1615.  
  1616.                         rotate_list(8,&seg->verts);
  1617.                         rotated=1;
  1618.  
  1619.                         for (i=0;i<4;i++)
  1620.                             codes_and &= Segment_points[seg->verts[sv[i]]].p3_codes;
  1621.  
  1622.                         if (codes_and & CC_BEHIND) continue;
  1623.  
  1624.                     }
  1625.                     child_list[n_children++] = c;
  1626.                 }
  1627.             }
  1628.  
  1629.             //now order the sides in some magical way
  1630.  
  1631.             if (new_seg_sorting)
  1632.                 sort_seg_children(seg,n_children,child_list);
  1633.  
  1634.             //for (c=0;c<MAX_SIDES_PER_SEGMENT;c++) {
  1635.             //  ch=seg->children[c];
  1636.  
  1637.             for (c=0;c<n_children;c++) {
  1638.                 int siden;
  1639.  
  1640.                 siden = child_list[c];
  1641.                 ch=seg->children[siden];
  1642.                 //if ( (window_check || !visited[ch])&& (WALL_IS_DOORWAY(seg, c))) {
  1643.                 {
  1644.                     if (window_check) {
  1645.                         int i;
  1646.                         ubyte codes_and_3d,codes_and_2d;
  1647.                         short _x,_y,min_x=32767,max_x=-32767,min_y=32767,max_y=-32767;
  1648.                         int no_proj_flag=0; //a point wasn't projected
  1649.  
  1650.                         if (rotated<2) {
  1651.                             if (!rotated)
  1652.                                 rotate_list(8,&seg->verts);
  1653.                             project_list(8,&seg->verts);
  1654.                             rotated=2;
  1655.                         }
  1656.  
  1657.                         for (i=0,codes_and_3d=codes_and_2d=0xff;i<4;i++) {
  1658.                             int p = seg->verts[Side_to_verts[siden][i]];
  1659.                             g3s_point *pnt = &Segment_points[p];
  1660.  
  1661.                             if (! (pnt->p3_flags&PF_PROJECTED)) {no_proj_flag=1; break;}
  1662.  
  1663.                             _x = f2i(pnt->p3_sx);
  1664.                             _y = f2i(pnt->p3_sy);
  1665.  
  1666.                             codes_and_3d &= pnt->p3_codes;
  1667.                             codes_and_2d &= code_window_point(_x,_y,check_w);
  1668.  
  1669.                             #ifndef NDEBUG
  1670.                             if (draw_edges) {
  1671.                                 gr_setcolor(BM_XRGB(31,0,31));
  1672.                                 gr_line(pnt->p3_sx,pnt->p3_sy,
  1673.                                     Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sx,
  1674.                                     Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sy);
  1675.                             }
  1676.                             #endif
  1677.  
  1678.                             if (_x < min_x) min_x = _x;
  1679.                             if (_x > max_x) max_x = _x;
  1680.  
  1681.                             if (_y < min_y) min_y = _y;
  1682.                             if (_y > max_y) max_y = _y;
  1683.  
  1684.                         }
  1685.  
  1686.                         #ifndef NDEBUG
  1687.                         if (draw_boxes)
  1688.                             draw_window_box(WHITE,min_x,min_y,max_x,max_y);
  1689.                         #endif
  1690.  
  1691.                         if (no_proj_flag || (!codes_and_3d && !codes_and_2d)) { //maybe add this segment
  1692.                             int rp = render_pos[ch];
  1693.                             window *new_w = &render_windows[lcnt];
  1694.  
  1695.                             if (no_proj_flag) *new_w = *check_w;
  1696.                             else {
  1697.                                 new_w->left  = max(check_w->left,min_x);
  1698.                                 new_w->right = min(check_w->right,max_x);
  1699.                                 new_w->top   = max(check_w->top,min_y);
  1700.                                 new_w->bot   = min(check_w->bot,max_y);
  1701.                             }
  1702.  
  1703.                             //see if this seg already visited, and if so, does current window
  1704.                             //expand the old window?
  1705.                             if (rp != -1) {
  1706.                                 if (new_w->left < render_windows[rp].left ||
  1707.                                          new_w->top < render_windows[rp].top ||
  1708.                                          new_w->right > render_windows[rp].right ||
  1709.                                          new_w->bot > render_windows[rp].bot) {
  1710.  
  1711.                                     new_w->left  = min(new_w->left,render_windows[rp].left);
  1712.                                     new_w->right = max(new_w->right,render_windows[rp].right);
  1713.                                     new_w->top   = min(new_w->top,render_windows[rp].top);
  1714.                                     new_w->bot   = max(new_w->bot,render_windows[rp].bot);
  1715.  
  1716.                                     if (no_migrate_segs) {
  1717.                                         //no_render_flag[lcnt] = 1;
  1718.                                         Render_list[lcnt] = -1;
  1719.                                         render_windows[rp] = *new_w;        //get updated window
  1720.                                         processed[rp] = 0;      //force reprocess
  1721.                                         goto no_add;
  1722.                                     }
  1723.                                     else
  1724.                                         Render_list[rp]=-1;
  1725.                                 }
  1726.                                 else goto no_add;
  1727.                             }
  1728.  
  1729.                             #ifndef NDEBUG
  1730.                             if (draw_boxes)
  1731.                                 draw_window_box(5,new_w->left,new_w->top,new_w->right,new_w->bot);
  1732.                             #endif
  1733.  
  1734.                             render_pos[ch] = lcnt;
  1735.                             Render_list[lcnt] = ch;
  1736.                             Seg_depth[lcnt] = l;
  1737.                             lcnt++;
  1738.                             if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
  1739.                             visited[ch] = 1;
  1740.  
  1741.                             #ifndef NDEBUG
  1742.                             if (pre_draw_segs)
  1743.                                 render_segment(ch);
  1744.                             #endif
  1745. no_add:
  1746.     ;
  1747.  
  1748.                         }
  1749.                     }
  1750.                     else {
  1751.                         Render_list[lcnt] = ch;
  1752.                         Seg_depth[lcnt] = l;
  1753.                         lcnt++;
  1754.                         if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
  1755.                         visited[ch] = 1;
  1756.                     }
  1757.                 }
  1758.             }
  1759.         }
  1760.  
  1761.         scnt = ecnt;
  1762.         ecnt = lcnt;
  1763.  
  1764.     }
  1765. done_list:
  1766.  
  1767.     lcnt_save = lcnt;
  1768.     scnt_save = scnt;
  1769.  
  1770.     first_terminal_seg = scnt;
  1771.     N_render_segs = lcnt;
  1772.  
  1773. }
  1774.  
  1775. //renders onto current canvas
  1776. void render_mine(int start_seg_num,fix eye_offset)
  1777. {
  1778.     int     i;
  1779.     int     nn;
  1780.  
  1781.     //  Initialize number of objects (actually, robots!) rendered this frame.
  1782.     Num_rendered_objects = 0;
  1783.  
  1784. #ifdef LASER_HACK
  1785.     Hack_nlasers = 0;
  1786. #endif
  1787.  
  1788.     #ifndef NDEBUG
  1789.     for (i=0;i<=Highest_object_index;i++)
  1790.         object_rendered[i] = 0;
  1791.     #endif
  1792.  
  1793.     //set up for rendering
  1794.  
  1795.     render_start_frame();
  1796.  
  1797.  
  1798.     #if defined(EDITOR) && !defined(NDEUBG)
  1799.     if (Show_only_curside) {
  1800.         rotate_list(8,&Cursegp->verts);
  1801.         render_side(Cursegp,Curside);
  1802.         goto done_rendering;
  1803.     }
  1804.     #endif
  1805.  
  1806.  
  1807.     #ifdef EDITOR
  1808.     if (_search_mode || eye_offset>0)   {
  1809.         //lcnt = lcnt_save;
  1810.         //scnt = scnt_save;
  1811.     }
  1812.     else
  1813.     #endif
  1814.         //NOTE LINK TO ABOVE!!
  1815.         build_segment_list(start_seg_num);      //fills in Render_list & N_render_segs
  1816.  
  1817.     //render away
  1818.  
  1819.     #ifndef NDEBUG
  1820.     if (!window_check) {
  1821.         Window_clip_left  = Window_clip_top = 0;
  1822.         Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
  1823.         Window_clip_bot   = grd_curcanv->cv_bitmap.bm_h-1;
  1824.     }
  1825.     #endif
  1826.  
  1827.     #ifndef NDEBUG
  1828.     if (!(_search_mode || eye_offset>0)) {
  1829.         int i;
  1830.  
  1831.         for (i=0;i<N_render_segs;i++) {
  1832.             int segnum;
  1833.  
  1834.             segnum = Render_list[i];
  1835.  
  1836.             if (segnum != -1)
  1837.                 if (visited2[segnum])
  1838.                     Int3();     //get Matt
  1839.                 else
  1840.                     visited2[segnum] = 1;
  1841.         }
  1842.     }
  1843.     #endif
  1844.  
  1845. //  if (!(_search_mode || eye_offset>0) && migrate_objects)
  1846.     if (!(_search_mode))
  1847.         build_object_lists(N_render_segs);
  1848.  
  1849.     if (eye_offset<=0)      // Do for left eye or zero.
  1850.         set_dynamic_light();
  1851.  
  1852.     if (!_search_mode && Clear_window == 2) {
  1853.         if (first_terminal_seg < N_render_segs) {
  1854.             int i;
  1855.  
  1856.             if (Clear_window_color == -1)
  1857.                 Clear_window_color = BM_XRGB(0, 0, 0);  //BM_XRGB(31, 15, 7);
  1858.     
  1859.             gr_setcolor(Clear_window_color);
  1860.     
  1861.             for (i=first_terminal_seg; i<N_render_segs; i++) {
  1862.                 if (Render_list[i] != -1) {
  1863.                     #ifndef NDEBUG
  1864.                     if ((render_windows[i].left == -1) || (render_windows[i].top == -1) || (render_windows[i].right == -1) || (render_windows[i].bot == -1))
  1865.                         Int3();
  1866.                     else
  1867.                     #endif
  1868.                         //NOTE LINK TO ABOVE!
  1869.                         gr_rect(render_windows[i].left, render_windows[i].top, render_windows[i].right, render_windows[i].bot);
  1870.                 }
  1871.             }
  1872.         }
  1873.     }
  1874.  
  1875.     for (nn=N_render_segs;nn--;) {
  1876.         int segnum;
  1877.         int objnp;
  1878.  
  1879.         // Interpolation_method = 0;
  1880.         segnum = Render_list[nn];
  1881.         Current_seg_depth = Seg_depth[nn];
  1882.  
  1883.         //if (!no_render_flag[nn])
  1884.         if (segnum!=-1 && (_search_mode || eye_offset>0 || visited[segnum]!=255)) {
  1885.             //set global render window vars
  1886.  
  1887.             if (window_check) {
  1888.                 Window_clip_left  = render_windows[nn].left;
  1889.                 Window_clip_top   = render_windows[nn].top;
  1890.                 Window_clip_right = render_windows[nn].right;
  1891.                 Window_clip_bot   = render_windows[nn].bot;
  1892.             }
  1893.  
  1894.             //mprintf((0," %d",segnum));
  1895.  
  1896.             render_segment(segnum); 
  1897.             visited[segnum]=255;
  1898.  
  1899.             if (window_check) {     //reset for objects
  1900.                 Window_clip_left  = Window_clip_top = 0;
  1901.                 Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
  1902.                 Window_clip_bot   = grd_curcanv->cv_bitmap.bm_h-1;
  1903.             }
  1904.  
  1905.             if (migrate_objects) {
  1906.                 //int n_expl_objs=0,expl_objs[5],i;
  1907.                 int listnum;
  1908.                 int save_linear_depth = Max_linear_depth;
  1909.  
  1910.                 Max_linear_depth = Max_linear_depth_objects;
  1911.  
  1912.                 listnum = nn;
  1913.  
  1914.                 //mprintf((0,"render objs seg %d",segnum));
  1915.  
  1916.                 for (objnp=0;render_obj_list[listnum][objnp]!=-1;)  {
  1917.                     int ObjNumber = render_obj_list[listnum][objnp];
  1918.  
  1919.                     if (ObjNumber >= 0) {
  1920.  
  1921.                         //mprintf( (0, "Type: %d\n", Objects[ObjNumber].type ));
  1922.     
  1923.                         //if (Objects[ObjNumber].type == OBJ_FIREBALL && n_expl_objs<5) {
  1924.                         //  expl_objs[n_expl_objs++] = ObjNumber;
  1925.                         //} else
  1926.                         #ifdef LASER_HACK
  1927.                         if (    (Objects[ObjNumber].type==OBJ_WEAPON) &&                                //if its a weapon
  1928.                                 (Objects[ObjNumber].lifeleft==Laser_max_time ) &&   //  and its in it's first frame
  1929.                                 (Hack_nlasers< MAX_HACKED_LASERS) &&                                    //  and we have space for it
  1930.                                 (Objects[ObjNumber].laser_info.parent_num>-1) &&                    //  and it has a parent
  1931.                                 ((Viewer-Objects)==Objects[ObjNumber].laser_info.parent_num)    //  and it's parent is the viewer
  1932.                            )        {
  1933.                             Hack_laser_list[Hack_nlasers++] = ObjNumber;                                //then make it draw after everything else.
  1934.                             //mprintf( (0, "O%d ", ObjNumber ));
  1935.                         } else  
  1936.                         #endif
  1937.                             do_render_object(ObjNumber);    // note link to above else
  1938.  
  1939.                         objnp++;
  1940.                     }
  1941.                     else {
  1942.  
  1943.                         listnum = -ObjNumber;
  1944.                         objnp = 0;
  1945.  
  1946.                     }
  1947.  
  1948.                 }
  1949.  
  1950.                 //for (i=0;i<n_expl_objs;i++)
  1951.                 //  do_render_object(expl_objs[i]);
  1952.  
  1953.                 //mprintf((0,"done seg %d\n",segnum));
  1954.  
  1955.                 Max_linear_depth = save_linear_depth;
  1956.  
  1957.             }
  1958.  
  1959.         }
  1960.     }
  1961.  
  1962.     //mprintf((0,"\n"));
  1963.  
  1964.                                 
  1965. #ifdef LASER_HACK                               
  1966.     // Draw the hacked lasers last
  1967.     for (i=0; i < Hack_nlasers; i++ )   {
  1968.         //mprintf( (0, "D%d ", Hack_laser_list[i] ));
  1969.         do_render_object(Hack_laser_list[i]);
  1970.     }
  1971. #endif
  1972.  
  1973.     // -- commented out by mk on 09/14/94...did i do a good thing??  object_render_targets();
  1974.  
  1975. #ifdef EDITOR
  1976.     #ifndef NDEUBG
  1977.     //draw curedge stuff
  1978.     if (Outline_mode) outline_seg_side(Cursegp,Curside,Curedge,Curvert);
  1979.     #endif
  1980.  
  1981. done_rendering:
  1982.     ;
  1983.  
  1984. #endif
  1985.  
  1986. }
  1987. #ifdef EDITOR
  1988.  
  1989. extern int render_3d_in_big_window;
  1990.  
  1991. //finds what segment is at a given x&y -  seg,side,face are filled in
  1992. //works on last frame rendered. returns true if found
  1993. //if seg<0, then an object was found, and the object number is -seg-1
  1994. int find_seg_side_face(short x,short y,int *seg,int *side,int *face,int *poly)
  1995. {
  1996.     _search_mode = -1;
  1997.  
  1998.     _search_x = x; _search_y = y;
  1999.  
  2000.     found_seg = -1;
  2001.  
  2002.     if (render_3d_in_big_window) {
  2003.         grs_canvas temp_canvas;
  2004.  
  2005.         gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
  2006.             LargeView.ev_canv->cv_bitmap.bm_w,LargeView.ev_canv->cv_bitmap.bm_h);
  2007.  
  2008.         gr_set_current_canvas(&temp_canvas);
  2009.  
  2010.         render_frame(0);
  2011.     }
  2012.     else {
  2013.         gr_set_current_canvas(&VR_render_sub_buffer[0]);    //render off-screen
  2014.         render_frame(0);
  2015.     }
  2016.  
  2017.     _search_mode = 0;
  2018.  
  2019.     *seg = found_seg;
  2020.     *side = found_side;
  2021.     *face = found_face;
  2022.     *poly = found_poly;
  2023.  
  2024. //  mprintf((0,"found seg=%d, side=%d, face=%d, poly=%d\n",found_seg,found_side,found_face,found_poly));
  2025.  
  2026.     return (found_seg!=-1);
  2027.  
  2028. }
  2029.  
  2030. #endif
  2031.